#include "stdafx.h"
#include "SoundManager.h"
#include <stdio.h>

SoundManager::SoundManager()
{
	soundCount = 0;

	sfxVolume = 1.0f;
	musicVolume = 1.0f;
	masterVolume = 0.5f;

	sfxChannel = nullptr;
	musicChannel = nullptr;
	masterChannel = nullptr;
}

SoundManager::~SoundManager()
{

}

int SoundManager::Initialize(void)
{
	/*
	Create a System object and initialize.
	*/
	result = FMOD::System_Create(&system);
	ERRCHECK(result);
	result = system->getVersion(&version);
	ERRCHECK(result);
	if (version < FMOD_VERSION)
	{
		printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n",
			version, FMOD_VERSION);
		return 0;
	}
	result = system->getNumDrivers(&numdrivers);
	ERRCHECK(result);
	if (numdrivers == 0)
	{
		result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
		ERRCHECK(result);
	}
	else
	{
		result = system->getDriverCaps(0, &caps, 0, &speakermode);
		ERRCHECK(result);
		/*
		Set the user selected speaker mode.
		*/
		result = system->setSpeakerMode(speakermode);
		ERRCHECK(result);
		if (caps & FMOD_CAPS_HARDWARE_EMULATED)
		{
			/*
			The user has the 'Acceleration' slider set to off! This is really bad
			for latency! You might want to warn the user about this.
			*/
			result = system->setDSPBufferSize(1024, 10);
			ERRCHECK(result);
		}
		result = system->getDriverInfo(0, name, 256, 0);
		ERRCHECK(result);
		if (strstr(name, "SigmaTel"))
		{
			/*
			Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
			PCM floating point output seems to solve it.
			*/
			result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0, 0,
				FMOD_DSP_RESAMPLER_LINEAR);
			ERRCHECK(result);
		}
	}

	result = system->init(100, FMOD_INIT_NORMAL, 0);
	if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
	{
		/*
		Ok, the speaker mode selected isn't supported by this soundcard. Switch it
		back to stereo...
		*/
		result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
		ERRCHECK(result);
		/*
		... and re-init.
		*/
		result = system->init(100, FMOD_INIT_NORMAL, 0);
	}
	ERRCHECK(result);


	system->createChannelGroup("SFXChannel", &sfxChannel);
	system->createChannelGroup("MusicChannel", &musicChannel);
	system->getMasterChannelGroup(&masterChannel);

	sfxChannel->setVolume(sfxVolume);
	musicChannel->setVolume(musicVolume);
	masterChannel->setVolume(masterVolume);

	LoadAllSounds();

	return 1;
}

void SoundManager::Shutdown(void)
{
	UnloadAllSounds();
	system->release();
}

void SoundManager::Update(void)
{
	system->update();
}

void SoundManager::UpdateEars(void)
{
	// TODO: Make parameters and set them
	system->set3DListenerAttributes(0, nullptr, nullptr, nullptr, nullptr);
}

void SoundManager::UpdateChannel(Object * object)
{
	for (unsigned int index = 0; index < channelLibrary.size(); index++)
	{
		if (channelLibrary[index].object == object)
			// TODO: Update pos and vel
			channelLibrary[index].channel->set3DAttributes(nullptr, nullptr);
	}
}

void SoundManager::UpdateVolumes(float sfx, float music, float master)
{
	sfxVolume = sfx;
	musicVolume = music;
	masterVolume = master;

	sfxChannel->setVolume(sfx);
	musicChannel->setVolume(music);
	masterChannel->setVolume(master);
}

void SoundManager::Load3DSound(const char * filename)
{
	Sound *	sound = nullptr;
	SoundInfo soundInfo;

	soundInfo.id = soundCount;
	soundInfo.type = SOUND_SAMPLE;
	soundLibrary.push_back(soundInfo);

	system->createSound(filename, FMOD_3D, 0, &sound);
	soundLibrary[soundInfo.id].sound = sound;

	soundCount++;
}

void SoundManager::LoadSFXSound(const char * filename)
{
	Sound *	sound = nullptr;
	SoundInfo soundInfo;

	soundInfo.id = soundCount;
	soundInfo.type = SOUND_SAMPLE;
	soundLibrary.push_back(soundInfo);

	system->createSound(filename, FMOD_DEFAULT, 0, &sound);
	soundLibrary[soundInfo.id].sound = sound;

	soundCount++;
}

void SoundManager::LoadMusicSound(const char * filename)
{
	Sound *	sound = nullptr;
	SoundInfo soundInfo;

	soundInfo.id = soundCount;
	soundInfo.type = SOUND_STREAM;
	soundLibrary.push_back(soundInfo);
	//testing 3D audio; TODO: remove 3D flag and set back to default
	system->createStream(filename, /*FMOD_DEFAULT*/ FMOD_3D | FMOD_LOOP_NORMAL, 0, &sound);
	soundLibrary[soundInfo.id].sound = sound;

	soundCount++;
}

void SoundManager::LoadAllSounds(void)
{
	LoadMusicSound("Resources/Sounds/Music/testMusic.wav");
	Load3DSound("Resources/Sounds/SFXs/test3DSFX.wav");
}

void SoundManager::UnloadAllSounds(void)
{
	while (!soundLibrary.empty())
	{
		soundLibrary.back().sound->release();
		soundLibrary.pop_back();
	}
}

Channel * SoundManager::Play3DSound(unsigned char sound, Object * object)
{
	// TODO: Make parameters for pos and vel and set them to the channel
	float volume = 0.0f;
	Channel * channel = nullptr;

	system->playSound(FMOD_CHANNEL_FREE, soundLibrary[sound].sound, false, &channel);
	sfxChannel->getVolume(&volume);
	channel->setVolume(volume);
	channel->setChannelGroup(sfxChannel);

	return channel;
}

void SoundManager::PlaySFXSound(unsigned char sound)
{
	float volume = 0.0f;
	Channel * channel = nullptr;

	system->playSound(FMOD_CHANNEL_FREE, soundLibrary[sound].sound, false, &channel);
	sfxChannel->getVolume(&volume);
	channel->setVolume(volume);
	channel->setChannelGroup(sfxChannel);
}

void SoundManager::PlayMusicSound(unsigned char sound)
{
	float volume = 0.0f;
	Channel * channel = nullptr;

	system->playSound(FMOD_CHANNEL_FREE, soundLibrary[sound].sound, false, &channel);
	musicChannel->getVolume(&volume);
	channel->setVolume(volume);
	channel->setChannelGroup(musicChannel);
}

void SoundManager::PauseAllSounds(void)
{
	masterChannel->setPaused(true);
}

void SoundManager::ResumeAllSounds(void)
{
	masterChannel->setPaused(false);
}

void SoundManager::ERRCHECK(FMOD_RESULT result)
{
	if (result != FMOD_OK)
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
}